﻿using System;
using System.CodeDom;
using System.Threading;
using Assets.Scripts.network.socket;
using UnityEngine;

namespace Assets.Scripts.network.socket
{
    public class GatewayClient
    {
        private GameSocketManager gameSocketManager;
        private GatewayInfo gatewayMessage;
        private HeartbeatManager heartbeatManager;
        private SynchronizationContext uiContext;

        public GatewayClient(GatewayInfo gatewayMessage, SynchronizationContext uiContext)
        {
            this.uiContext = uiContext;
            this.gatewayMessage = gatewayMessage;
            string host = gatewayMessage.Ip;
            int port = gatewayMessage.Port;
            gameSocketManager = new GameSocketManager(host, port);
            heartbeatManager = new HeartbeatManager(this,gameSocketManager, GameClientConfig.EnableHeartbeat);
        }
        private void ActionInUIThread(SendOrPostCallback callback)
        {
            uiContext.Send(callback, null);
        }
        /// <summary>
        /// 判断网络是否可用，只能在主线程池中调用
        /// </summary>
        /// <returns></returns>
        public bool IsNetReachable()
        {
            return Application.internetReachability != NetworkReachability.NotReachable;
        }

        public void AddSocketChangeStateListener(Action<SocketStateEnum> listener, Type classType)
        {
            gameSocketManager.AddSocketStateChangeListener((state) =>
            {
                ActionInUIThread(obj =>
                {
                    listener.Invoke(state);
                });
            }, classType);
        }
        public void SubscribeServerPushMessageHandler<T>(Action<IGameMessage> callback) where T : IGameMessage
        {
            Type messageType = typeof(T);
            IGameMessage gameMessage = Activator.CreateInstance<T>();
            void pushCallback(IGameMessage response)
            {
                ActionInUIThread(obj =>
                {
                    callback.Invoke(response);
                });
            }
            PushMessageInfo pushMessageInfo = new PushMessageInfo
            {
                Callback = pushCallback,
                GameMessageType = messageType
            };
            int messageId = gameMessage.GetHeader().MessageId;
            gameSocketManager.AddPushMessageCallback(messageId, pushMessageInfo);
        }

        public GatewayInfo GetGatewayMessage()
        {
            return gatewayMessage;
        }
        public void Send<T>(IGameMessage gameMessage, Action<IGameMessage> callback) where T : IGameMessage
        {

            gameSocketManager.Send<T>(gameMessage, (data) =>
            {
                heartbeatManager.UpdateLastResponseTime();
                ActionInUIThread(obj =>
                {
                    callback.Invoke(data);
                });
            });
            heartbeatManager.UpdateLastRequestTime();
        }

        public void Connect(Action<SocketStateEnum> callback)
        {

            gameSocketManager.ConnectServer(socketState =>
            {
                if (socketState == SocketStateEnum.ConnectSuccess)
                {
                    //heartbeatManager.Start();
                }
                callback.Invoke(socketState);
            });
        }
        public bool IsConnected()
        {
            return gameSocketManager.IsConnected();
        }

        public void Shutdown()
        {
            gameSocketManager.Shutdown();
            heartbeatManager.Shutdown();
        }
    }
}


